using System; // 引入基础系统命名空间，提供基本的类型和功能
using System.Collections.Concurrent; // 引入并发集合命名空间，提供线程安全的集合类型
using System.IO; // 引入输入输出命名空间，用于文件和目录操作
using System.Threading; // 引入线程命名空间，提供线程同步和计时器功能
using System.Threading.Tasks; // 引入任务命名空间，支持异步编程

namespace PT.Common // 定义PT.Common命名空间，用于组织相关的类和类型
{
    /// <summary>
    /// 异步日志写入器类，提供异步写入日志的功能
    /// 支持按文件后缀分类日志、批量写入、定时写入以及文件大小限制
    /// </summary>
    public static class LogAsyncWriter
    {
        /// <summary>
        /// 日志队列字典，用于存储不同后缀的日志队列
        /// 键为文件后缀，值为对应的日志队列实例
        /// 使用ConcurrentDictionary确保线程安全
        /// </summary>
        private static readonly ConcurrentDictionary<string, LogQueue> _logQueues = new();
        
        /// <summary>
        /// 单个日志文件的最大大小限制（10MB）
        /// 当日志文件达到此大小时会创建新的日志文件
        /// </summary>
        private const int MaxFileSize = 10 * 1024 * 1024; // 10MB
        
        /// <summary>
        /// 批量写入的日志条数阈值
        /// 当队列中的日志条数达到此值时会触发批量写入
        /// </summary>
        private const int BatchSize = 10;
        
        /// <summary>
        /// 日志刷新间隔时间（30秒）
        /// 每隔此时间会自动将队列中的日志写入文件
        /// </summary>
        private const int FlushInterval = 30000; // 30秒

        /// <summary>
        /// 写入日志的公共静态方法（基础版本）
        /// </summary>
        /// <param name="message">要写入的日志消息内容</param>
        /// <param name="fileSuffix">日志文件后缀，用于区分不同类型的日志文件，默认为空字符串</param>
        public static void WriteLog(string message, string fileSuffix = "")
        {
            // 获取或创建指定后缀的日志队列
            // 如果指定后缀的日志队列已存在则直接返回，否则创建新的日志队列
            var queue = _logQueues.GetOrAdd(fileSuffix, suffix =>
            {
                // 创建新的日志队列实例
                var q = new LogQueue(suffix);
                // 启动日志队列的处理流程
                q.StartProcessing();
                return q;
            });

            // 将日志消息添加到队列中
            queue.Enqueue(message);
        }

        /// <summary>
        /// 写入带时间统计的日志的公共静态方法（重载版本）
        /// </summary>
        /// <param name="message">要写入的日志消息内容</param>
        /// <param name="fileSuffix">日志文件后缀，用于区分不同类型的日志文件</param>
        /// <param name="startTime">操作开始时间</param>
        /// <param name="endTime">操作结束时间</param>
        public static void WriteLog(string message, string fileSuffix, DateTime startTime, DateTime endTime)
        {
            // 计算操作耗时
            var duration = endTime - startTime;
            // 构造包含时间统计信息的日志消息
            var durationMessage = $"{message} [开始时间: {startTime:yyyy-MM-dd HH:mm:ss.fff}] [结束时间: {endTime:yyyy-MM-dd HH:mm:ss.fff}] [用时: {duration.TotalSeconds:F3}s]";
            
            // 获取或创建指定后缀的日志队列
            // 如果指定后缀的日志队列已存在则直接返回，否则创建新的日志队列
            var queue = _logQueues.GetOrAdd(fileSuffix, suffix =>
            {
                // 创建新的日志队列实例
                var q = new LogQueue(suffix);
                // 启动日志队列的处理流程
                q.StartProcessing();
                return q;
            });

            // 将包含时间统计信息的日志消息添加到队列中
            queue.Enqueue(durationMessage);
        }

        /// <summary>
        /// 日志队列内部类，负责处理日志的异步写入
        /// 包含日志队列、定时器以及文件写入逻辑
        /// </summary>
        private class LogQueue
        {
            /// <summary>
            /// 线程安全的日志消息队列，用于存储待写入的日志消息
            /// </summary>
            private readonly ConcurrentQueue<string> _messages = new();
            
            /// <summary>
            /// 定时器，用于定期触发日志写入操作
            /// </summary>
            private readonly Timer _flushTimer;
            
            /// <summary>
            /// 日志文件后缀，用于构建日志文件名
            /// </summary>
            private readonly string _fileSuffix;
            
            /// <summary>
            /// 当前批次中的日志条数计数器
            /// </summary>
            private int _currentBatchCount;
            
            /// <summary>
            /// 当前日志文件的大小（字节）
            /// </summary>
            private long _currentFileSize;
            
            /// <summary>
            /// 当前日志文件的完整路径
            /// </summary>
            private string _currentFilePath;

            /// <summary>
            /// LogQueue构造函数
            /// </summary>
            /// <param name="fileSuffix">日志文件后缀</param>
            public LogQueue(string fileSuffix)
            {
                // 设置文件后缀，如果为空或空白则使用空字符串，否则加上下划线前缀
                _fileSuffix = string.IsNullOrWhiteSpace(fileSuffix) ? "" : $"_{fileSuffix}";
                // 初始化定时器，但不启动它（使用无穷大时间间隔）
                _flushTimer = new Timer(Flush, null, Timeout.Infinite, Timeout.Infinite);
            }

            /// <summary>
            /// 启动日志处理流程
            /// </summary>
            public void StartProcessing()
            {
                // 启动定时器，设置首次触发时间为FlushInterval毫秒后，之后不再自动触发
                _flushTimer.Change(FlushInterval, Timeout.Infinite);
            }

            /// <summary>
            /// 将日志消息添加到队列中
            /// </summary>
            /// <param name="message">要添加的日志消息</param>
            public void Enqueue(string message)
            {
                // 将带有时间戳的日志消息添加到队列中
                _messages.Enqueue($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} - {message}");
                // 原子性地增加当前批次计数器，如果达到批次大小则触发刷新
                if (Interlocked.Increment(ref _currentBatchCount) >= BatchSize)
                {
                    Flush(null);
                }
            }

            /// <summary>
            /// 刷新日志队列，将队列中的日志写入文件
            /// </summary>
            /// <param name="state">定时器回调状态参数（未使用）</param>
            private async void Flush(object state)
            {
                // 暂停定时器，防止重复触发
                _flushTimer.Change(Timeout.Infinite, Timeout.Infinite);

                try
                {
                    // 创建一个列表来存储要写入的消息
                    var messagesToWrite = new System.Collections.Generic.List<string>();
                    // 从队列中取出最多BatchSize条消息
                    while (_messages.TryDequeue(out var message) && messagesToWrite.Count < BatchSize)
                    {
                        messagesToWrite.Add(message);
                    }

                    // 如果有消息需要写入，则执行写入操作
                    if (messagesToWrite.Count > 0)
                    {
                        await WriteToFile(messagesToWrite);
                    }
                }
                finally
                {
                    // 重置当前批次计数器为0
                    Interlocked.Exchange(ref _currentBatchCount, 0);
                    // 重新启动定时器
                    _flushTimer.Change(FlushInterval, Timeout.Infinite);
                }
            }

            /// <summary>
            /// 将日志消息写入文件
            /// </summary>
            /// <param name="messages">要写入的日志消息列表</param>
            /// <returns>异步任务</returns>
            private async Task WriteToFile(System.Collections.Generic.List<string> messages)
            {
                try
                {
                    // 获取当前日期用于构建日志文件名
                    var today = DateTime.Now.ToString("yyyy-MM-dd");
                    // 构建日志目录路径
                    var logDirectory = Path.Combine(Directory.GetCurrentDirectory(), "logs");

                    // 如果日志目录不存在则创建
                    if (!Directory.Exists(logDirectory))
                    {
                        Directory.CreateDirectory(logDirectory);
                    }

                    // 检查是否需要创建新文件
                    if (string.IsNullOrEmpty(_currentFilePath) ||
                        !File.Exists(_currentFilePath) ||
                        _currentFileSize >= MaxFileSize)
                    {
                        // 构建新的日志文件路径
                        _currentFilePath = Path.Combine(logDirectory, $"{today}{_fileSuffix}.log");
                        // 重置文件大小计数器
                        _currentFileSize = 0;

                        // 如果文件已存在，获取当前大小
                        if (File.Exists(_currentFilePath))
                        {
                            var fileInfo = new FileInfo(_currentFilePath);
                            _currentFileSize = fileInfo.Length;
                        }
                    }

                    // 构建要写入的内容
                    var content = string.Join(Environment.NewLine, messages) + Environment.NewLine;
                    // 计算内容的字节大小
                    var contentSize = System.Text.Encoding.UTF8.GetByteCount(content);

                    // 如果写入后超过最大文件大小，创建新文件
                    if (_currentFileSize + contentSize > MaxFileSize)
                    {
                        var counter = 1;
                        var newFilePath = Path.Combine(logDirectory, $"{today}{_fileSuffix}_{counter}.log");

                        // 查找合适的文件名（文件大小不超过限制）
                        while (File.Exists(newFilePath))
                        {
                            var fileInfo = new FileInfo(newFilePath);
                            if (fileInfo.Length + contentSize <= MaxFileSize)
                            {
                                break;
                            }
                            counter++;
                            newFilePath = Path.Combine(logDirectory, $"{today}{_fileSuffix}_{counter}.log");
                        }

                        // 更新当前文件路径和大小
                        _currentFilePath = newFilePath;
                        _currentFileSize = new FileInfo(_currentFilePath).Length;
                    }

                    // 异步追加内容到文件
                    await File.AppendAllTextAsync(_currentFilePath, content);
                    // 更新当前文件大小
                    _currentFileSize += contentSize;
                }
                catch
                {
                    // 日志写入失败处理
                    // 在实际应用中可能需要记录此错误或采取其他措施
                }
            }
        }
    }




    /* -----------------------------
    人工智能辅助提示词
    生成一个.net8的写日志类，可异步写日志。
    提供PT.Common.log.WriteLog静态函数写日志，第一个参数为日志内容文本，第二个参数为日志文件名后缀。
    日志文件名，命令规范，日期+后缀=文件名
    满足每30秒或积累10条日志时批量写入、单个文件不超过10MB的需求
    不要引用第三方库 
    -----------------------------------
    */



}
